package ce.com.cenewbluesdk.bluetooth;

import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

import ce.com.cenewbluesdk.CEBC;
import ce.com.cenewbluesdk.uitl.BluetoothDeviceReflect;
import ce.com.cenewbluesdk.uitl.BtBondReceiver;
import ce.com.cenewbluesdk.uitl.Lg;

/**
 * Created by Administrator on 2016/11/15 0015.
 */
public class CEBlueTooth_3 extends CEBlueToothBase {


    private Context context;

    @Override
    public synchronized void connect(String mac) {

        if (mDevice != null
                && mDevice.getAddress() != null
                && mDevice.getAddress().equals(mac)
                && (blueConnectState == CEBC.BLUE_CONNECTING || blueConnectState == CEBC.BLUE_CONNECTED)) {
            Lg.e("本次连接将不会执行，当前连接状态："+blueConnectState+
                    "  连接的地址mDevice 地址 ："+mDevice.getAddress()+"  mac:"+mac);
            return;
        }
        Lg.e( "开始连接：" + mac);
        if (mAdapter == null) {
            disconnectAndCallback();
            return;
        }
        try {
            /**
             * 获取Device对象, 只是验证mac地址是否有效, 可以在mAdapter.isEnabled()之前调用,
             * (三星手机上, 一定要在判断蓝牙是否打开前调用, 防止mDevice为null)
             * */
            mDevice = mAdapter.getRemoteDevice(mac);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
            disconnectAndCallback();
            return;
        }

        if (!mAdapter.isEnabled()) {
            disconnectAndCallback();
            return;
        }

        disconnect();
        mWorkThread = new WorkThread();
        if (mWorkThread.init(mDevice)) {
            mWorkThread.start();
            return;
        } else {
            return;
        }
    }

    @Override
    public void disConnect() {
        disconnect();
    }

    @Override
    public void sendData(byte[] bytes) {
        write(bytes);
    }

    @Override
    public void sendData(int index, byte[] bytes) {
        write(bytes);
    }

    private BluetoothDevice mDevice;

    private static final UUID UUID_SPP = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
    private final BluetoothAdapter mAdapter;
    private WorkThread mWorkThread;

    private Handler mHandler = new Handler(Looper.getMainLooper());

    public CEBlueTooth_3(Context mContext) {
        context = mContext;
        mAdapter = BluetoothAdapter.getDefaultAdapter();
    }

    public boolean write(byte[] out) {
        WorkThread t;
        // 创建临时的TransThread, 使写数据的操作, 不在同步块中
        synchronized (this) {
            if (mWorkThread == null || mWorkThread.mOutStream == null) {
                dataSendFailed(out);
                return false;
            }
            t = mWorkThread;
        }
        return t.write(out);
    }

    public synchronized void disconnect() {
        if (mWorkThread != null) {
            mWorkThread.cancel();
            mWorkThread.mOutStream = null;
            mWorkThread = null;
        }
    }

    private void disconnectAndCallback() {
        disconnect();
        blueToothConnectStateChange(CEBC.BLUE_DISCONNECT);
    }

    private boolean mUseSecureRfcomm = true;
    private boolean mAutoBond = true;

    /**
     * 是否自动配对
     *
     * @param autoBond
     */
    public void setAutoBond(boolean autoBond) {
        mAutoBond = autoBond;
    }

    /**
     * 是否使用安全版的Rfcomm; 默认为true
     *
     * @param enable 若为true, 则会弹配对框
     */
    public void setUseSecureRfcomm(boolean enable) {
        mUseSecureRfcomm = enable;
    }

    public boolean isUseSecureRfcomm() {
        return mUseSecureRfcomm;
    }

    /**
     * 在某些手机上, 配对框弹出比较慢, 导致配对框接收不到配对完成的广播, 导致配对框不消失...
     * 故延时一下~~
     *
     * @param delay -1, 表示立即确定, 不延时;
     *              在demo中测试, 500ms差不多, 但在App中, 填2000ms都没什么效果, 原因未知
     */

    private void setPairingConfirmDelay(long delay) {
        mPairingConfirmDelay = delay;
    }

    private long mPairingConfirmDelay = 500;

    private class WorkThread extends Thread {

        private boolean needdisconnect = false;

        private boolean isConnecting = false;

        private BluetoothSocket mSocket;

        private InputStream mInStream;
        private OutputStream mOutStream;
        private BluetoothDevice mDevice;
        private Context mContext = context;
        private BtBondReceiver mReceiver;
        private Runnable mPairingConfirmRunnable = new Runnable() {
            @Override
            public void run() {
                BluetoothDeviceReflect.setPairingConfirmation(mDevice, true);
            }
        };

        public WorkThread() {
            super(WorkThread.class.getSimpleName());
        }

        @TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1)
        private boolean init(BluetoothDevice device) {
            mDevice = device;
            try {

                if (mUseSecureRfcomm) {
                    mSocket = device.createRfcommSocketToServiceRecord(UUID_SPP);
                } else {
                    mSocket = device.createInsecureRfcommSocketToServiceRecord(UUID_SPP);
                }
            } catch (IOException e) {
                e.printStackTrace();
                disconnectAndCallback();
                return false;
            }
            return true;
        }

        private void registerBondReceiver() {
            mReceiver = new BtBondReceiver() {
                @TargetApi(Build.VERSION_CODES.KITKAT)
                @Override
                protected void onPairingRequest(BluetoothDevice device, int pairingVariant, int paringKey) {
                    switch (pairingVariant) {
                        case BluetoothDeviceReflect.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
                        case BluetoothDeviceReflect.PAIRING_VARIANT_CONSENT:
                            if (device.getAddress().equals(mDevice.getAddress())) {
                                if (mPairingConfirmDelay < 0) {
                                    mPairingConfirmRunnable.run();
                                } else {// 大于等于0, 则延时确定
                                    mHandler.postDelayed(mPairingConfirmRunnable, mPairingConfirmDelay);
                                }
                            }
                            break;
                    }
                }
            };
            mReceiver.register(mContext);// 广播可以在子线程中注册...
        }

        private void unregisterBondReceiver() {
            mReceiver.unregister(mContext);
            mHandler.removeCallbacks(mPairingConfirmRunnable);
        }

        @Override
        public void run() {
            // 关闭发现
            mAdapter.cancelDiscovery();
            // 连接
            try {
                if (mAutoBond) {
                    registerBondReceiver();
                }
                try {
                    Thread.sleep(100);// 延时100ms, 并不一定有效果~~
                } catch (InterruptedException e) {
                    e.printStackTrace();

                }

                if (needdisconnect) {
                    this.cancel();
                    return;
                }
                isConnecting = true;
                Log.e("liu", "开始连接");
                blueToothConnectStateChange(CEBC.BLUE_CONNECTING);
                mSocket.connect();
                Log.e("liu", "连接完成");
                isConnecting = false;
                if (needdisconnect) {
                    Log.e("liu", "连接成功后，需要断开");
                    this.cancel();
                    return;
                }
            } catch (IOException | NullPointerException e) {
                // 在api18的手机上, 蓝牙未打开, 会报null异常
                e.printStackTrace();
                isConnecting = false;
                disconnectAndCallback();
                Log.e("liu", "Socket连接异常:" + e.toString());

                return;
            } finally {
                if (mAutoBond) {
                    unregisterBondReceiver();
                }
            }
            // 获取读写流
            try {
                mInStream = mSocket.getInputStream();
                mOutStream = mSocket.getOutputStream();
                Log.e("liu", "流获取成功");

            } catch (IOException e) {
                Log.e("liu", "流获取失败");
                e.printStackTrace();
                disconnectAndCallback();
                return;
            }
            // 连接成功
            blueToothConnectStateChange(CEBC.BLUE_CONNECTED);

            // 循环读取数据
            byte[] buffer = new byte[20];
            while (true) try {
                int length = mInStream.read(buffer);
                byte[] bytes = new byte[length];
                System.arraycopy(buffer, 0, bytes, 0, length);
                Lg.e("蓝牙3.0 收到设备侧的数据 <<<<<：" + CEBC.byte2hex(bytes));
                blueToothReceiptDate(bytes);

            } catch (IOException e) {
                e.printStackTrace();
                disconnectAndCallback();
                return;
            }
        }

        public boolean write(byte[] bytes) {
            Lg.e("蓝牙3.0 写给设备测的数据：" + CEBC.byte2hex(bytes));
            try {
                mOutStream.write(bytes);
                dataSendSucceed(bytes);
            } catch (IOException e) {
                e.printStackTrace();
                dataSendFailed(bytes);
                return false;
            }
            return true;
        }

        public void cancel() {
            needdisconnect = true;

            if (!isConnecting) {
                close(mSocket);
            } else {
                Log.e("liu", "连接过程中请求中断    以前的 这里会有问题");
            }
            if (mSocket != null) {
                BluetoothDevice device = mSocket.getRemoteDevice();
                if (device.getBondState() == BluetoothDevice.BOND_BONDING) {
                    BluetoothDeviceReflect.cancelBondProcess(device);
                }
            }
            this.interrupt();// 唤醒sleep


        }
    }


    public static void close(Closeable... c) {
        for (Closeable closeable : c) {
            if (closeable != null) {
                try {
                    closeable.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }


}
